package ModelAndController;
/*
 * Megjelenítésért felelős osztály. A file kiírásokat és beolvasásokat kezeli,
 * valamint a parancsértelmező is itt helyezkedik el.
 */
import java.io.*;
import java.util.Scanner;
import java.util.StringTokenizer;
public class View {
	//referencia a controllerre
	protected Controller control;
	protected FileWriter fstream;
	protected BufferedWriter out;
	protected InputStreamReader isr;
    protected BufferedReader br;
    protected StringTokenizer stk;
    protected String commandLine;
    protected boolean shouldExit;
    protected boolean commandWasHandled;
    protected String[] commandFileContent;
    protected int nbOfCommand;
	//konstruktor a kontroller referenciájával	
	public View(Controller refToController) {
		control = refToController;
		shouldExit = false;
		nbOfCommand = 1;
		//takarítás
	    try{
	    // file létrehozás/törlés
	    	fstream = new FileWriter("Output.txt");
	    	out = new BufferedWriter(fstream);
	    	out.close();
	    	isr = new InputStreamReader(System.in);
		    br = new BufferedReader(isr);
	    }catch (Exception e){
	    	print("Ismeretlen hiba tortent! "+e.getMessage());
	    }
	}

	//A konzolos parancsértelmező függvény
	public void commandInterpreter(){
		try{
			commandLine = null;
			while( !shouldExit ){
				print(nbOfCommand+". parancs:");
				commandWasHandled = false;
				getCommandAndDecideWhatToDo( br.readLine() );
				commandLine = null;
			}
		}catch(Exception e){
			print("Ismeretlen hiba tortent! "+e.getMessage());
		}
	}
	//a beolvasott parancsot megkapja a függvény,felismeri,hogy mit kapott
	private void getCommandAndDecideWhatToDo(String line){
		commandLine = line;
		stk = new StringTokenizer( line );
		
		String command = "";
		if( stk.hasMoreTokens() )
			command = stk.nextToken();
		
		if(command.toLowerCase().contentEquals("create"))
			create();
		
	    if(command.toLowerCase().contentEquals("execute"))
	    	execute();
	    
	    if(command.toLowerCase().contentEquals("getswitch"))
	    	control.getSwitch();
	    
	    if(command.toLowerCase().contentEquals("setswitch"))
	    	setSwitch();
	    
	    if(command.toLowerCase().contentEquals("getsignal"))
	    	control.getSignal();
	    
	    if(command.toLowerCase().contentEquals("setsignal"))
	    	setSignal();
	    
	    if(command.toLowerCase().contentEquals("getdisplay"))
	    	control.getDisplay();
	    
	    if(command.toLowerCase().contentEquals("getscope"))
	    	getScope();
	    
	    if(command.toLowerCase().contentEquals("step"))  
	    	step();
	    
	    if(command.toLowerCase().contentEquals("setstablelimit"))
	    	setStableLimit();
	    
	    if(command.toLowerCase().contentEquals("exit")){
	    	print("Terminated");
	    	shouldExit = true;
	    }
	    
	    if( !commandWasHandled )
	    	print("Command not recognized! "+commandLine);
	    
	}
	//hálózat létrehozása parancs
	private void create(){
		if( !stk.hasMoreTokens() )
			print("Txt file not found!");
		else{
			String fileName = stk.nextToken();
			control.create(fileName);
		}
	}
	//parancsfájl beolvasása parancs
	private void execute(){
		if( !stk.hasMoreTokens() )
			print("No file name given!");
		else{
			String fileName = stk.nextToken();
			File file= new File(fileName);
			if(!file.exists()){
				print("File doesn't exists! "+fileName);
				return;
			}
			
			readFileAndFillCommandFileContent(file);
			print("Executing command "+fileName);
			
			//Executing to fileContent
			for(int act=0; act<commandFileContent.length; act++)
				if( !commandFileContent[act].contentEquals("") ){
					print(nbOfCommand+". parancs:");
					commandWasHandled = false;
					getCommandAndDecideWhatToDo( commandFileContent[act] );
					commandLine = null;
				}
		}
	}
	//parancsfájl beolvasása és parancslista feltöltése
	private void readFileAndFillCommandFileContent(File file){
		try{
			Scanner reader = new Scanner(file);
			int countLines = 0;
			while( reader.hasNextLine() ){
				reader.nextLine();
				countLines++;
			}
		
			commandFileContent = new String[countLines];
			reader = new Scanner(file);
			countLines = 0;
			while( reader.hasNextLine() ){
				commandFileContent[countLines] = reader.nextLine();
				countLines++;
			}
		}catch(Exception e){
			print("Error at the execution "+e.getMessage());
		}
	}
//kapcsoló beállítása
	private void setSwitch(){
		if( !stk.hasMoreTokens() )
			print("No switch with ID=");
		else{
			String swID = stk.nextToken();
			int switchID = -1;
			boolean shouldContinue = true;
			try{
				switchID = Integer.parseInt( swID );
			}catch(Exception e){
				print("No switch with ID="+swID);
				shouldContinue = false;
			}
			
			if( shouldContinue )
				control.setSwitch(switchID);
		}
	}
	//jelgenerátor beállítása
	private void setSignal(){
		if( !stk.hasMoreTokens() )
			print("No signalGenerator with ID=");
		else{
			String sgID = stk.nextToken();
			int signalID = -1;
			boolean shouldContinue = true;
			try{
				signalID = Integer.parseInt( sgID );
			}catch(Exception e){
				print("No signalGenerator with ID="+sgID);
				shouldContinue = false;
			}
			
			if(shouldContinue && stk.hasMoreTokens()){
				int[] values = null;
				try{
					String valueString = "";
					while( stk.hasMoreTokens())
					valueString = valueString.concat( stk.nextToken()+" ");
					values = ParseNewStateArrayForSignalGenerator( valueString, true );
				}catch(Exception e){
					print( e.getMessage() );
					return;
				}
				control.setSignal(signalID, values);
			}
			else
				print("New values must be given for signalGenerator");
		}
	}
	//oszcilloszkópok kiolvasása
	private void getScope(){
		//Egy scope listazasa
		if( stk.hasMoreTokens() ){
			String secondToken = stk.nextToken();
			int value = -1;
			try{
				value = Integer.parseInt( secondToken );
			}catch(Exception e){
				print("Number forma error: "+secondToken);
				return;
			}
			control.getScope(value);
		}
		//Osszes scope listazasa
		else
			control.getScope();
	}
	//ütemezési ciklus léptetése
	private void step(){
		
		if(stk.hasMoreTokens()){
			String secondToken = stk.nextToken();
			//Reszletes kell
			if(secondToken.toLowerCase().contentEquals("list")){
				//Reszletes, es composite 
				if(stk.hasMoreTokens()){
					int[] values = null;
					String valueString = "";
					while(stk.hasMoreTokens())
						valueString = valueString.concat( stk.nextToken()+" ");
					try{
					values = ParseNewStateArrayForSignalGenerator( valueString, false);
					}catch(Exception e){
						print( e.getMessage() );
						return;
					}
					control.stepList(values);
				}
				//
				else{
					control.stepList();
				}
			}
			//Adott szamot lepjunk elore
			else{
				int stepNum = 0;
				try{
					stepNum = Integer.parseInt( secondToken );
				}catch(Exception e){
					print("Problem with the following number's format: "+secondToken);
					return;
				}
				control.step(stepNum);
			}
		}
		else
			control.step();
	}
	//maximum ciklusszám beállítása
	private void setStableLimit(){
		int temp = -1;
		boolean shouldContinue = true;
		if( !stk.hasMoreTokens() ){
			print("Maximum loop number in schedule needed for this command!");
			shouldContinue = false;
		}
		if( shouldContinue ){
			shouldContinue = true;
			String tempString = stk.nextToken();
			try{
				temp = Integer.parseInt( tempString );
			}catch(Exception e){
				shouldContinue = false;
				print("This format is not good for maximum loop number in schedule: "+tempString);
			}
			if( shouldContinue )
				control.setStableLimit(temp);
		}
	}
	// konzolra és fájlba író függvény
	public void print(String text){
		commandWasHandled = true;
		//kapott szöveg kiírása a konzolra
		System.out.println(text);
		//kapott szöveg kiírása fájlba
	    try{
	    	if( !text.contains("parancs:") ){
	    		// file megnyitás
	    		fstream = new FileWriter("Output.txt", true);
	    		out = new BufferedWriter(fstream);
	    		if( commandLine != null){
	    			out.write("% "+nbOfCommand+". Command: "+commandLine);
	    			nbOfCommand++;
	    			out.newLine();
	    		}
	    		out.write(text);
	    		out.newLine();
	    		out.newLine();
	    		out.close();
	    	}
	    }catch (Exception e){
	    	//kivételek elkapása
	    	print("Ismeretlen hiba tortent! "+e.getMessage());
	    }
	}
	//jelgenerátor számára értékeket kiolvasó és formázó függvény
	private int[] ParseNewStateArrayForSignalGenerator(String line, boolean shouldCheckValues) throws Exception{
		int[] retValue;
		
		StringTokenizer tksForArray =new StringTokenizer(line);
		int countTokens = 0;
		while( tksForArray.hasMoreTokens()){
			tksForArray.nextToken();
			countTokens++;
		}
		
		retValue = new int[countTokens];
		countTokens = 0;
		tksForArray = new StringTokenizer(line);
		
		while( tksForArray.hasMoreTokens()){
			String tempString = tksForArray.nextToken();
			
			int temp = 0;
			try{
				temp = Integer.parseInt( tempString );
			}catch(Exception e){
				throw new Exception("One of the number's format is not acceptable: "+tempString);
			}
			retValue[ countTokens ] = temp;
			
			if( shouldCheckValues && retValue[countTokens] != 0 && retValue[countTokens] != 1)
				throw new Exception("One of the new values are not acceptable: "+retValue[countTokens]);
			countTokens++;
		}
		
		return retValue;
	}
}
